//------------------------------------------------------------------------------
// <copyright file="UserDefinedTypeHooks.cpp" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

#include "stdafx.h"
#include "UserDefinedTypeHooks.h"
#include <string>

#define CHK_ARG(expr) { if(!(expr)) { CHK(E_INVALIDARG); } else { CHK(S_OK); } }

const DWORD ExpectedNumSpells = 4;
const DWORD ExpectedNumWeapons = 2;

namespace Microsoft { namespace Internal { namespace GamesTest { namespace Rpc { namespace Server { namespace TestHooks
{
	RpcHookCode InputPlayerNoOutput(RpcArchive& input, RpcArchive& output)
	{
		UNREFERENCED_PARAMETER(output);

		HRESULT hr = E_FAIL;
		Player p;

		RpcArchive playerArchive;
		CHK(input.GetNamedValue(L"playerData", &playerArchive));

		CHK(Player::FromRpcArchive(playerArchive, &p));

		CHK(VerifyIncomingPlayerData(p));
end:
		return hr;
	}

	RpcHookCode NoInputPlayerOutput(RpcArchive& input, RpcArchive& output)
	{
		UNREFERENCED_PARAMETER(input);
		UNREFERENCED_PARAMETER(output);

		HRESULT hr = E_FAIL;

		Player p;
		InitializeOutgoingPlayer(&p);

		CHK(p.ToRpcArchive(&output));
end:
		return hr;
	}

	RpcHookCode InputPlayerOutputPlayer(RpcArchive& input, RpcArchive& output)
	{
		HRESULT hr = E_FAIL;

		CHK(InputPlayerNoOutput(input, output));
		CHK(NoInputPlayerOutput(input, output));
end:
		return hr;
	}

	RpcHookCode VerifyIncomingPlayerData(const Player& playerData)
	{
		HRESULT hr = E_FAIL;

		CHK_ARG(fabs(playerData.health - 76.375f) < 0.0001);
		CHK_ARG(wcscmp(playerData.name, L"Brian The Awesome") == 0);
		CHK_ARG(playerData.numSpells == ExpectedNumSpells);

		CHK_ARG(wcscmp(playerData.spells[0], L"Heal") == 0);
		CHK_ARG(wcscmp(playerData.spells[1], L"Rage") == 0);
		CHK_ARG(wcscmp(playerData.spells[2], L"Morph") == 0);
		CHK_ARG(wcscmp(playerData.spells[3], L"Haste") == 0);

		CHK_ARG(playerData.numWeapons == ExpectedNumWeapons);

		CHK_ARG(playerData.weapons[0].damage == 1411518807);
		CHK_ARG(fabs(playerData.weapons[0].modifier - 64848978978.8971) < 0.0001);

		CHK_ARG(playerData.weapons[1].damage == 576460752);
		CHK_ARG(fabs(playerData.weapons[1].modifier - -1796456897.68642) < 0.0001);

		CHK_ARG(playerData.stature.height == 73);
		CHK_ARG(playerData.stature.weight == 189);
end:
		return hr;
	}

	void InitializeOutgoingPlayer(Player* p)
	{
		std::wstring name(L"Ragnor The Terrible");
		p->name = new wchar_t[name.length() + 1];
		wcsncpy_s(p->name, name.length() + 1, name.c_str(), name.length() + 1);

		p->health = 0.34245f;

		p->numSpells = ExpectedNumSpells;
		std::wstring spell1(L"Fireball");
		std::wstring spell2(L"Freeze");
		std::wstring spell3(L"Hurricane");
		std::wstring spell4(L"Force");
		// The addition of the extra ExpectedNumSpells on the next line is to make room for the null-terminator for each string.
		p->spells = (wchar_t**)malloc((ExpectedNumSpells * sizeof(wchar_t*)) + (spell1.length() + spell2.length() + spell3.length() + spell4.length() + ExpectedNumSpells) * sizeof(wchar_t));

		wchar_t* stringContentStart = (wchar_t*)(p->spells + ExpectedNumSpells);
		p->spells[0] = stringContentStart;
		p->spells[1] = p->spells[0] + spell1.length() + 1;
		p->spells[2] = p->spells[1] + spell2.length() + 1;
		p->spells[3] = p->spells[2] + spell3.length() + 1;

		wcsncpy_s(p->spells[0], spell1.length() + 1, spell1.c_str(), spell1.length() + 1);
		wcsncpy_s(p->spells[1], spell2.length() + 1, spell2.c_str(), spell2.length() + 1);
		wcsncpy_s(p->spells[2], spell3.length() + 1, spell3.c_str(), spell3.length() + 1);
		wcsncpy_s(p->spells[3], spell4.length() + 1, spell4.c_str(), spell4.length() + 1);

		p->numWeapons = ExpectedNumWeapons;
		p->weapons = new Weapon[ExpectedNumWeapons];
		p->weapons[0].damage = 13454;
		p->weapons[0].modifier = -0.6;
		p->weapons[1].damage = 923;
		p->weapons[1].modifier = 2.4534;

		p->stature.height = 82;
		p->stature.weight = 63;
	}

}}}}}}